package com.yuanda.erp9.syn.service.erp9.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yuanda.erp9.syn.contant.RateCalculateConstants;
import com.yuanda.erp9.syn.entity.CmsBrandsTempEntity;
import com.yuanda.erp9.syn.entity.CmsGoodsEntity;
import com.yuanda.erp9.syn.entity.CmsGoodsInformationEntity;
import com.yuanda.erp9.syn.entity.CmsPricesEntity;
import com.yuanda.erp9.syn.enums.CachePrefixEnum;
import com.yuanda.erp9.syn.enums.DeliveryAreaEnum;
import com.yuanda.erp9.syn.enums.SourceEnum;
import com.yuanda.erp9.syn.exception.ServerPrepareException;
import com.yuanda.erp9.syn.exception.TargetServerException;
import com.yuanda.erp9.syn.execule.thread.Master;
import com.yuanda.erp9.syn.helper.FutureExcelHelper;
import com.yuanda.erp9.syn.helper.RetryOperateLogHelper;
import com.yuanda.erp9.syn.poi.FutureExcelData;
import com.yuanda.erp9.syn.pojo.CmsGoodsPojo;
import com.yuanda.erp9.syn.service.erp9.CmsTopicUpdateSumLogService;
import com.yuanda.erp9.syn.service.erp9.FutureExcelService;
import com.yuanda.erp9.syn.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * @ClassName FutureExcelServiceImpl
 * @Description
 * @Date 2022/12/1
 * @Author myq
 */
@Slf4j
@Service
public class FutureExcelServiceImpl implements FutureExcelService {

    @Autowired
    private FutureExcelHelper futureExcelHelper;

    @Autowired
    private CmsTopicUpdateSumLogService cmsTopicUpdateSumLogService;

    @Autowired
    private RetryOperateLogHelper retryOperateLogHelper;

    private final String US_CODE = "US000000011";
    private final String SUPPLIER = "Future Electronics";

    /**
     * 下载地址
     */
    private final String in = "http://datauphk.b1b.com/INV_SHARE_in.xlsx";
    private final String out = "http://datauphk.b1b.com/INV_SHARE_out.xlsx";

    /**
     * 临时文件
     */
    private final String temporaryInFileName = "INV_SHARE_in_.xlsx";
    private final String temporaryOutFileName = "INV_SHARE_out.xlsx";

    /**
     * 重试开关、重试次数
     */
    private AtomicInteger retryMaxCount = new AtomicInteger(0);

    /**
     * @Description: 解析excel
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2022/12/116:33
     */
    @Override
    public void parse(Long pk) {
        CacheUtil.Cache brandCache = CacheUtil.init(CachePrefixEnum.BRAND.getKey());
        CacheUtil.Cache supplierCache = CacheUtil.init(CachePrefixEnum.SUPPLIERS.getKey());
        Integer supplierId = supplierCache.get(SUPPLIER);
        Master<CmsGoodsPojo> objectMaster = null;
        String canonicalPath = null;
        try {
            File f = new File("");
            canonicalPath = f.getCanonicalPath();
            log.info("==============获取服务器父路径：" + canonicalPath + "==============");
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 多线开始下载文件
        downloadingFile(canonicalPath);
        // 读取本地excel并合并成一个list
        List<FutureExcelData> futureExcelDatas = null;
        try {
            log.info("***************准备合并Future数据******************");
            futureExcelDatas = readHttpExcel(canonicalPath);
        } catch (Exception e) {
            log.error("Future>>>>>>>>>>>>>>读取合并excel异常");
            throw new TargetServerException("Future>>>>>>>>>>>>>>读取合并excel异常:" + e);
        }

        log.info("合并后的长度： " + futureExcelDatas.size());
        if (CollectionUtils.isEmpty(futureExcelDatas)) {
            return;
        }
        AtomicInteger sum = new AtomicInteger(0);
        objectMaster = new Master<>(supplierId, null, SourceEnum.DATA_PACKAGE.getCode());
        try {
            Iterator<FutureExcelData> iterator = futureExcelDatas.iterator();
            while (iterator.hasNext()) {
                FutureExcelData futureExcelData = iterator.next();
                try {
                    sum.incrementAndGet();
                    // 包装类
                    CmsGoodsPojo cmsGoodsPojo = new CmsGoodsPojo();
                    //商品类
                    CmsGoodsEntity cmsGoodsEntity = new CmsGoodsEntity();
                    cmsGoodsEntity.setAdminid(0);
                    cmsGoodsEntity.setTenantsid(0);
                    cmsGoodsEntity.setClassifyid(0);
                    cmsGoodsEntity.setImg("");
                    cmsGoodsEntity.setType(0);
                    cmsGoodsEntity.setStatus(1);
                    cmsGoodsEntity.setStatusMsg("");
                    cmsGoodsEntity.setDataType(1);
                    cmsGoodsEntity.setModel(futureExcelData.getMpn());
                    CmsBrandsTempEntity cmsBrandsTempEntity = new CmsBrandsTempEntity();
                    cmsBrandsTempEntity.setTag(0);
                    cmsBrandsTempEntity.setName(futureExcelData.getMfrName());
                    Integer brandId = brandCache.insertAndGet(cmsBrandsTempEntity);
                    cmsGoodsEntity.setBrand(brandId);
                    cmsGoodsEntity.setBrandName(futureExcelData.getMfrName());
                    cmsGoodsEntity.setSupplier(supplierId);
                    cmsGoodsEntity.setSplName(SUPPLIER);
                    String incodes = EasyExcelUtils.getIncodes(futureExcelData.getUniqueID() + "-" + futureExcelData.getUserType(), US_CODE, supplierId);
                    cmsGoodsEntity.setIncodes(incodes);
                    cmsGoodsEntity.setGoodid(incodes);
                    cmsGoodsEntity.setIsSampleApply(0);
                    cmsGoodsEntity.setBatch(StringUtils.isEmpty(futureExcelData.getDateCode()) ? "" : futureExcelData.getDateCode());
                    cmsGoodsEntity.setOriginalPrice(new BigDecimal("0.00"));
                    cmsGoodsEntity.setPurchasePrice(new BigDecimal("0.00"));
                    int count = Integer.parseInt(futureExcelData.getAts());
                    cmsGoodsEntity.setRepertory(count);
                    cmsGoodsEntity.setRepertoryArea(futureExcelHelper.getDepot(futureExcelData.getRegion()));
                    cmsGoodsEntity.setPublish(1);
                    cmsGoodsEntity.setDescribe(futureExcelData.getDescription());
                    cmsGoodsEntity.setFiles("");
                    cmsGoodsEntity.setSource(SourceEnum.DATA_PACKAGE.getCode());
                    cmsGoodsEntity.setPayType(0);

                    if (count > 0) {
                        String delivery = futureExcelHelper.getDelivery(futureExcelData.getRegion());
                        cmsGoodsEntity.setDomesticDate(delivery);
                        cmsGoodsEntity.setHongkongDate("5-8工作日");
                    } else {
                        cmsGoodsEntity.setDomesticDate("期货");
                        cmsGoodsEntity.setHongkongDate("期货");
                    }

                    long num = !StringUtils.isEmpty(futureExcelData.getMpq()) ? Long.parseLong(futureExcelData.getMpq()) : 1;
                    cmsGoodsEntity.setIncremental(num);
                    cmsGoodsEntity.setMpq(num);
                    cmsGoodsEntity.setHisp(null);
                    cmsGoodsEntity.setSales(0);
                    cmsGoodsEntity.setClick(0);
                    cmsGoodsEntity.setVisitor(0);
                    cmsGoodsEntity.setCreatedAt(DateUtils.now());
                    cmsGoodsEntity.setUpdatedAt(DateUtils.now());
                    cmsGoodsEntity.setActivityId(0);
                    cmsGoodsEntity.setContent(null);
                    cmsGoodsEntity.setEccnNo(futureExcelData.getEccn());
                    //费率
                    JSONObject data = RateCalculateUtil.getRate(cmsGoodsEntity.getBrandName(), cmsGoodsEntity.getModel());
                    // 费率信息
                    JSONObject rateJsonObject = (JSONObject) data.get(RateCalculateConstants.RATE);
                    cmsGoodsEntity.setRates(rateJsonObject);
                    //关税
                    BigDecimal tariffRate = rateJsonObject.getBigDecimal(RateCalculateConstants.TARIFFRATE_FIELD);
                    //商检税
                    BigDecimal cIQprice = rateJsonObject.getBigDecimal(RateCalculateConstants.CIQPRICE_FIELD);
                    //税费计算和存储
                    if (tariffRate != null) {
                        cmsGoodsEntity.setTariffsRate(tariffRate.doubleValue());
                    }
                    if (cIQprice != null) {
                        cmsGoodsEntity.setInspectionChargesFee(cIQprice.doubleValue());
                    }
                    cmsGoodsEntity.setEmbargo(data.get(RateCalculateConstants.EMBARGO_FIELD) == null ? 0 : data.getInteger(RateCalculateConstants.EMBARGO_FIELD));
                    cmsGoodsEntity.setCcc(data.get(RateCalculateConstants.CCC_FIELD) == null ? 0 : data.getInteger(RateCalculateConstants.CCC_FIELD));
                    cmsGoodsEntity.setEccnNo(data.getString(RateCalculateConstants.ECCN_FIELD));

                    // 参数
                    Map<String, String> paramMap = new LinkedHashMap<>();
                    paramMap.put("ECCN", futureExcelData.getEccn());
                    paramMap.put("COO", futureExcelData.getCoo());
                    paramMap.put("HTSCODE", futureExcelData.getHtsCode());
                    paramMap.put("HTSCODE_FULL", futureExcelData.getHtscodeFull());
                    String userType = futureExcelData.getUserType();
                    switch (userType) {
                        case "NORTEC":
                            paramMap.put("适用用户", "in");
                            break;
                        case "HKHOGY":
                            paramMap.put("适用用户", "out");
                            break;
                        default:
                            break;
                    }
                    cmsGoodsEntity.setParams(JSON.toJSONString(paramMap));
                    // 阶梯价格
                    List<Map<String, String>> ladderPrice = futureExcelHelper.getLadderPrice(
                            Arrays.asList(futureExcelData.getPriceQty1(), futureExcelData.getPriceQty2(), futureExcelData.getPriceQty3(),
                                    futureExcelData.getPriceQty4(), futureExcelData.getPriceQty5(), futureExcelData.getPriceQty6()),
                            Arrays.asList(futureExcelData.getPriceBreak1(), futureExcelData.getPriceBreak2(), futureExcelData.getPriceBreak3(),
                                    futureExcelData.getPriceBreak4(), futureExcelData.getPriceBreak5(), futureExcelData.getPriceBreak6()),
                            userType, futureExcelData.getUniqueID());

                    // price
                    List<CmsPricesEntity> pricesEntities = new ArrayList<>(6);
                    for (Map<String, String> m : ladderPrice) {
                        CmsPricesEntity pricesEntity = new CmsPricesEntity();
                        pricesEntity.setLadderid(0);
                        pricesEntity.setGoodid(incodes);
                        pricesEntity.setMin(Long.parseLong(m.get("min")));
                        pricesEntity.setMax(Long.parseLong(m.get("max")));
                        pricesEntity.setPrice(BigDecimal.valueOf(Double.parseDouble(m.get("price"))));
                        pricesEntity.setCurrency(Integer.parseInt(m.get("currency")));
                        pricesEntity.setPosition(Integer.parseInt(m.get("position")));
                        pricesEntity.setDiscountRate(new BigDecimal(m.get("discount_rate")));
                        pricesEntity.setDiscountPrice(new BigDecimal(m.get("discount_price")));
                        pricesEntity.setPublish(0);
                        pricesEntity.setCreatedAt(new Date());
                        pricesEntity.setUpdatedAt(new Date());
                        pricesEntities.add(pricesEntity);
                    }
                    cmsGoodsPojo.setCmsPricesEntityList(pricesEntities);

                    long minQty = Long.parseLong(futureExcelData.getMinqty());
                    cmsGoodsEntity.setMinimumOrder((minQty == 0L ? 1L : minQty));
                    if (!CollectionUtils.isEmpty(ladderPrice)) {
                        //当供应商有最小起订金额时,计算最小起订量
                        Long moq = MoqUtil.getMoq(minQty, cmsGoodsEntity.getIncremental(), new BigDecimal("10"), pricesEntities);
                        if (moq == null) {
                            cmsGoodsEntity.setMinimumOrder(Long.parseLong(ladderPrice.get(0).get("min")));
                        }else {
                            cmsGoodsEntity.setMinimumOrder(MultipleUtil.getMinimumByMultiple(minQty, moq));
                        }
//                        cmsGoodsEntity.setUnitPrice(Double.parseDouble(MathUtil.divide(ladderPrice.get(0).get("price"), cmsGoodsEntity.getMinimumOrder(), 4)));
                    } else {
                        cmsGoodsEntity.setUnitPrice(0.0000);
                    }
                    cmsGoodsEntity.setPrices(JSON.toJSONString(ladderPrice));
                    cmsGoodsEntity.setDeliveryArea(DeliveryAreaEnum.OTHER.getCode());
                    cmsGoodsPojo.setCmsGoodsEntity(cmsGoodsEntity);

                    CmsGoodsInformationEntity cmsGoodsInformationEntity = new CmsGoodsInformationEntity();
                    cmsGoodsInformationEntity.setEcnn(1);
                    cmsGoodsInformationEntity.setAtlas("");
                    cmsGoodsInformationEntity.setContent(futureExcelData.getDescription());
                    cmsGoodsInformationEntity.setActivity(0);
                    cmsGoodsInformationEntity.setEcnnnumber("");
                    cmsGoodsInformationEntity.setTariffs(0);
                    cmsGoodsInformationEntity.setGoodid(incodes);
                    cmsGoodsInformationEntity.setTariffsrate(0);
                    cmsGoodsInformationEntity.setInspectionCharges(0);
                    cmsGoodsInformationEntity.setInspectionChargesFee(cmsGoodsEntity.getInspectionChargesFee());
                    cmsGoodsInformationEntity.setParams(paramMap);
                    cmsGoodsInformationEntity.setCreatedAt(new Date());
                    cmsGoodsPojo.setCmsGoodsInformationEntity(cmsGoodsInformationEntity);

                    objectMaster.add(cmsGoodsPojo);
                    iterator.remove();
                } catch (Exception e) {
                    log.warn("解析future数据异常，将丢弃此条数据: {1}", e);
                    retryOperateLogHelper.add(futureExcelData, supplierId, e.toString());
                }
            }
        } finally {
            // 退出标志
            objectMaster.isBegin = false;
            cmsTopicUpdateSumLogService.insertBySum(sum.longValue(), pk);
        }
    }


    /**
     * @param canonicalPath
     * @Description: 开启俩个线程下载in和out。xlsx
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/313:42
     */
    private void downloadingFile(String canonicalPath) {
        CountDownLatch c = new CountDownLatch(2);
        String localInExcelPath = canonicalPath + "/";
        new Thread(() -> {
            try {
                ManyThreadFileDownloadUtil.commitTask(in, localInExcelPath, temporaryInFileName);
                log.info("###############INV_SHARE_IN下载完成#################");
            } catch (Exception e) {
                log.info("###############INV_SHARE_IN下载异常:{}#####################", e);
                if (retryMaxCount.incrementAndGet() <= 1) {
                    log.warn("开启重试，重试次数：" + retryMaxCount);
                    downloadingFile(canonicalPath);
                }
            }
            c.countDown();
        }, "INV_SHARE_IN").start();

        String localOutExcelPath = canonicalPath + "/";
        new Thread(() -> {
            try {
                ManyThreadFileDownloadUtil.commitTask(out, localOutExcelPath, temporaryOutFileName);
                log.info("###############INV_SHARE_OUT下载完成#################");
            } catch (Exception e) {
                log.info("###############INV_SHARE_OUT下载异常:{}#####################", e);
                if (retryMaxCount.incrementAndGet() <= 1) {
                    log.warn("开启重试，重试次数：" + retryMaxCount);
                    downloadingFile(canonicalPath);
                }
            }
            c.countDown();
        }, "INV_SHARE_OUT").start();

        try {
            c.await((int) (1000 * 60 * 60 * 2), TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * @Description: 读取SHARE_in.xlsx 和SHARE_out.xlsx, 带优化可以使用多线程下载加快处理速度。
     * @Params:
     * @Return:
     * @Author: Mr.myq
     * @Date: 2023/2/213:46
     */
    public List<FutureExcelData> readHttpExcel(String canonicalPath) throws Exception {
        log.info("*********************开始读取Future本地文件**********************");
        CountDownLatch countDownLatch = new CountDownLatch(2);
        List<FutureExcelData> shareOrderList = new ArrayList<>();
        String localInExcelPath = canonicalPath + "/" + temporaryInFileName;
        Map<String, FutureExcelData> outMap = new HashMap<>();
        String localOutExcelPath = canonicalPath + "/" + temporaryOutFileName;
        try {
            new Thread(() -> {
                //in
                try {
//                    EasyExcelUtils.readExcel("C:\\Users\\myq\\Desktop\\" + temporaryInFileName, FutureExcelData.class, new Consumer<FutureExcelData>() {
                    EasyExcelUtils.readExcel(localInExcelPath, FutureExcelData.class, new Consumer<FutureExcelData>() {
                        @Override
                        public void accept(FutureExcelData futureExcelData) {
                            futureExcelData.setUserType("NORTEC");
                            shareOrderList.add(futureExcelData);
                        }
                    });
                } finally {
                    countDownLatch.countDown();
                }
            }, "read-share_in_excel").start();

            new Thread(() -> {
                // out
                try {
                    EasyExcelUtils.readExcel(localOutExcelPath, FutureExcelData.class, new Consumer<FutureExcelData>() {
                        //                    EasyExcelUtils.readExcel("C:\\Users\\myq\\Desktop\\" + temporaryOutFileName, FutureExcelData.class, new Consumer<FutureExcelData>() {
                        @Override
                        public void accept(FutureExcelData futureExcelData) {
                            futureExcelData.setUserType("HKHOGY");
                            outMap.put(futureExcelData.getUniqueID(), futureExcelData);
                        }
                    });
                } finally {
                    countDownLatch.countDown();
                }
            }, "read-share_out_excel").start();

            countDownLatch.await();
            log.info(">>>>>>>>>>>>>>>>>>>全部读取完成<<<<<<<<<<<<<<<<<<<<<<<");
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("********************读取excel异常*****************");
            throw new ServerPrepareException("读取excel异常:" + e.toString());
        }

        // 增强代码逻辑以及代码健壮性
        if (CollectionUtils.isEmpty(shareOrderList) || MapUtils.isEmpty(outMap)) {
            log.error("*****************Future数据:{in[size=" + shareOrderList.size() + "] | out[size=" + outMap.size() + "]},下载程序可能发生异常或文件为空********************");
            return Collections.emptyList();
        }

        // marge and ordered list
        List<FutureExcelData> margeList = new ArrayList<>();
        Iterator<FutureExcelData> iterator = shareOrderList.iterator();
        while (iterator.hasNext()) {
            FutureExcelData next = iterator.next();
            margeList.add(next);
            FutureExcelData futureExcelData = outMap.get(next.getUniqueID());
            margeList.add(futureExcelData);

            iterator.remove();
            outMap.remove(next.getUniqueID());
        }

        log.info("************************Future合并完成**************************");
        return margeList;
    }


}
